<?php

    class Core_Exception extends Exception {
        private $__type;
        public function __construct($msg,$type){
            parent::__construct($msg);

            $this->__type = $type;
        }
        public function type(){
            return $this->__type;
        }
    }
    define("EX_NONCRIT",0);
    define("EX_CRIT",   1);
    
    //------------------------------------------------------------------
	abstract class core_controller {
		public function dispatch(){
			
		}
	}
	
	 //simple controllers - move them to the correct place
	 
	 /*	Proxy controller. Use this to change the way application works at core start.
	  * 
	  * 
	  * 
	  */
    
    class core_controller_proxy extends core_controller {
		protected $__poi;
		
		public function __construct(){
			if ($this->authentificate()){
				$this->__poi = new core_controller_display();
			}else{
				$this->__poi = new core_controller_unauthorised();
			}
		}
		
		final public function dispatch(){
			if ($this->__poi){
				$this->__poi->dispatch();
			}else{
				throw new Core_Exception("Failed to dispatch core controller, no point of implement.", ER_CRIT);
			}
		}
		
		public function authentificate(){
			#return true;	//todo: set a auth proxy there
			return context::get("auth")->authentificate();
			//TODO: introduce some policies there
		}
	}
	
	/*
	 * 	Basic display controller.
	 * 
	 * 
	 */
	
	class core_controller_display extends core_controller{
		public function __construct(){
			
		}
		
		public function dispatch(){
			try {
				$module_name = context::get("request")->get_module_name();
				$request_tokens = array();
				
				#-------------------------------------------------------
				foreach ($_REQUEST as $key=>$val){
					$request_tokens[] = "{$key}={$val}";
				}
				//todo - replace with context::request()->serialize()
				
				context::get("tpl")->assign("__CORE",
					array(
						"module"=>$module_name,
						"request"=>implode("&",$request_tokens)
					)
				);
				
				if ($module_name){
					$module = context::get("module_factory")->produce($module_name);
					
					#hackhackhack
					#default module is probably blocked for us
					if (!$module){
						$module_name = $_SESSION["permissions"][0]["name"];
						$module = context::get("module_factory")->produce($module_name);
					}
					#hackhackhack
					
					$module_content = $module->fetch();

					context::get("view")->display($module_content);
					
					#echo $content;
					
				}else{
					context::get("io")->debug("no module name specified", IO_DEBUG_WARNING);
				}
			}
			catch (IO_Exception $io_e){
				//do something
			}
		}
	}
	
	
	//------------------------------------------------------------------
	//	Do there something if user is not authorised. Display a logon page or whatever
	//------------------------------------------------------------------
	
    class core_controller_unauthorised  extends core_controller {
		public function __construct(){
			context::get("auth")->logout();	//cleanup session
		}
		
		public function dispatch(){
			context::get("view")->flush();
			context::get("view")->add_viewport("login");
			context::get("view")->display();
		}
	}
	
	//------------------------------------------------------------------
	//	install shit
	//------------------------------------------------------------------
	
	class core_install_controller extends core_controller {
		public function dispatch(){

			context::install();	//specific shit
			
			//todo: just run default core controller
			//override auth module
			
			//hack hack hack
			context::get("auth")->authentificate();
			
			context::get("view")->flush();
			context::get("view")->add_viewport("install");
			context::get("view")->display();
			//hack hack hack
		}
	}
    
    //==================================================================
    //			NFO2 Core class. Loads shit and runs controllers.
	//==================================================================

    class core {

        public function __construct(){
            try{
				set_include_path(dirname(__FILE__));
				
                spl_autoload_extensions(".class.php");
                
                spl_autoload_register();
                spl_autoload_register(array($this,"core_autoload_libs"));	//core libs
                spl_autoload_register(array($this,"autoload_libs"));		//project libs
                spl_autoload_register(array($this,"autoload_project_classes"));		//project libs

				include_once(dirname(__FILE__).DIRECTORY_SEPARATOR."utils.php");

                $this->preload();
                
                #ini_set("open_basedir",context::get("path")->get_root().DIRECTORY_SEPARATOR."..");
            }
            catch (Core_Exception $e){
                $this->handle_core_exception($e);
            }
            
        }
        
        public function set_project($project_name){
			context::get("project_mgr")->set_project($project_name);
			context::get("config")->load_cfg_enviroment();					//load project-specific enviroment
			
			//Важное замечание: загрузка файла с проектом должна происходить ПОСЛЕ вызова load_cfg_enviroment();
			
			//TODO:refact me1111 Move me to project or whatever!
			if (is_file($project_path = context::get("path")->get_root()._DRS."classes"._DRS.$project_name.".prj.php")){
				require_once($project_path);
			}else{
				context::get("io")->debug("failed to locate default project file {project_name}/classes/{project_name}.php", IO_DEBUG_WARNING);
			}
		}
        
        //--------------------------------------------------------------
        private function preload(){
			$config = context::get("config");
			$config->load_cfg_enviroment();					//load nfo2 core configuration
			
			#time to set table prefix
			DEFINE("NFO2_DB_PREFIX",$config["table_prefix"]);	
		}
		
		//--------------------------------------------------------------
		public function dispatch(){
			
			try{
				$controller = new core_controller_proxy();
				$controller->dispatch();
			}
            catch (Core_Exception $e){
                $this->handle_core_exception($e);
            }

		}
		
		//--------------------------------------------------------------
		public function install(){
			
			try{
				$controller = new core_install_controller();
				$controller->dispatch();
			}
            catch (Core_Exception $e){
                $this->handle_core_exception($e);
            }

		}

        private function handle_core_exception($e){
			#context::get("io")->trace();
			#context::get("io")->dump($e->getTrace());
			
            switch ($e->type()){
                case EX_NONCRIT:
                    context::get("io")->msg("<span style='color:darkorange;'>Non-crit core exception: ".$e->getMessage()."</span>");			//wrong!
                break;

                case EX_CRIT:
					context::get("io")->msg("<span style='color:red;'>Crit core exception: ".$e->getMessage()."</span>");			//wrong!
                break;
            }
        }
        
        private function core_autoload_libs($name){
			$path = context::get("path")->get_core_root()._DRS."libs"._DRS.$name._DRS.$name.".class.php";
			return $this->autoload_class($name, $path);
		}
		
        private function autoload_libs($name){
			$path = context::get("path")->get_root()._DRS."libs"._DRS.$name._DRS.$name.".class.php";
			return $this->autoload_class($name, $path);
		}
		
        private function autoload_project_classes($name){
			$path = context::get("path")->get_root()._DRS."classes"._DRS.$name.".class.php";
			return $this->autoload_class($name, $path);
		}
		
		private function autoload_class($name, $path){
			
			if (is_file($path)){
				require_once($path);
			}else{
				#throw new Core_Exception("file '{$path}' not found",EX_NONCRIT);
				return false;
			}
			
			if (!class_exists($name)){
				#throw new Core_Exception("library class {$name} not found",EX_NONCRIT);
			}else{
				return true;
			}
			
			return false;
		}
		
		//TODO 
        
    }


?>
